//--------------------------------------------------------------------------
// 
//  Copyright (c) Chili Software.  All rights reserved. 
// 
//  File: ObjectContextFactoryPolicyBase.cs
//
//  Description: The ObjectContextFactory policy base class.
// 
//--------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;

namespace Chili.Opf3
{
	/// <summary>
	/// Class that represents the <see cref="ObjectContextFactory">ObjectContextFactory</see>'s 
	/// policy base class. It needs to be implemented by policies and holds the logic for creating
	/// new <see cref="ObjectContext">ObjectContext</see> instances.
	/// </summary>
	/// <example>
	/// This example shows how to set up the factory to create an ObjectContext instance for each new thread.
	/// <code lang="CS">
	/// // Set the policy for multi threading.
	/// ObjectContext.Factory.Policy = new PerThreadObjectContextFactoryPolicy(delegate()
	/// {
	///     MsSqlStorage storage = new MsSqlStorage("... connection string ...");
	///     ObjectContext ctx = new ObjectContext(storage);
	///
	///     return ctx;
	/// });
	/// 
	/// // ... Other code
	/// 
	/// // Have an ObjectContext instance created
	/// ObjectContext context = ObjectContext.Factory.GetObjectContext();
	/// </code>
	/// </example>
	public abstract class ObjectContextFactoryPolicyBase
	{
		private ObjectContextFactoryCreatorDelegate _objectContextCreator;

		/// <summary>
		/// Creates a new instance of the <see cref="ObjectContextFactoryPolicyBase">ObjectContextFactoryPolicyBase Class</see>.
		/// </summary>
		/// <param name="creator">The delegate that creates new <see cref="ObjectContext">ObjectContext</see> instances.</param>
		public ObjectContextFactoryPolicyBase(ObjectContextFactoryCreatorDelegate creator)
		{
			if (creator == null)
				throw new ArgumentNullException("creator");

			_objectContextCreator = creator;
		}

		/// <summary>
		/// Returns an <see cref="ObjectContext">ObjectContext</see> instance.
		/// </summary>
		/// <returns>An <see cref="ObjectContext">ObjectContext</see> instance.</returns>
		internal ObjectContext GetObjectContext()
		{
			ObjectContext result = null;

			// Check if a new ObjectContexgt is required.
			if (IsNewObjectContextRequired())
			{
				// Create a new one.
				ObjectContext context = _objectContextCreator();
				// Throw an exception if no instance is returned. That is not allowed.
				if (context == null)
					throw new NullReferenceException("ObjectContextCreator must return an ObjectContext instance.");

				// Store the new instance.
				result = StoreNewObjectContext(context);
			}
			else
			{
				// Return an existing instance if no new is required.
				result = GetExistingObjectContext();
			}

			if (result == null)
				throw new NullReferenceException("The ObjectContextFactory must return a valid ObjectContext instance.");

			return result;
		}

		/// <summary>
		/// Returns whether a new <see cref="ObjectContext">ObjectContext</see> instance is required.
		/// </summary>
		/// <returns>True if a new instance is required; false otherwise.</returns>
		protected abstract bool IsNewObjectContextRequired();

		/// <summary>
		/// Stores the new <see cref="ObjectContext">ObjectContext</see> instance.
		/// </summary>
		/// <param name="context">The <see cref="ObjectContext">ObjectContext</see> to store.</param>
		/// <returns>The <see cref="ObjectContext">ObjectContext</see> instance that has been stored.</returns>
		protected abstract ObjectContext StoreNewObjectContext(ObjectContext context);

		/// <summary>
		/// Gets an existing <see cref="ObjectContext">ObjectContext</see> instance.
		/// </summary>
		/// <returns>An <see cref="ObjectContext">ObjectContext</see> instance.</returns>
		protected abstract ObjectContext GetExistingObjectContext();
	}
}
